﻿using System;

namespace Aeon.Emulator.Decoding.Recompiler
{
    /// <summary>
    /// Identifies the address of a compiled block of code.
    /// </summary>
    internal struct BlockAddress : IEquatable<BlockAddress>
    {
        private uint offset;
        private ushort segment;

        /// <summary>
        /// Initializes a new instance of the BlockAddress struct.
        /// </summary>
        /// <param name="segment">Segment/selector of the address.</param>
        /// <param name="offset">Offset of the address.</param>
        public BlockAddress(ushort segment, uint offset)
        {
            this.offset = offset;
            this.segment = segment;
        }

        /// <summary>
        /// Tests for equality between two BlockAddresses.
        /// </summary>
        /// <param name="valueA">First address.</param>
        /// <param name="valueB">Second address.</param>
        /// <returns>True if addresses are equal; otherwise false.</returns>
        public static bool operator ==(BlockAddress valueA, BlockAddress valueB)
        {
            return valueA.Equals(valueB);
        }
        /// <summary>
        /// Tests for inequality between two BlockAddresses.
        /// </summary>
        /// <param name="valueA">First address.</param>
        /// <param name="valueB">Second address.</param>
        /// <returns>True if addresses are not equal; otherwise false.</returns>
        public static bool operator !=(BlockAddress valueA, BlockAddress valueB)
        {
            return !valueA.Equals(valueB);
        }

        /// <summary>
        /// Tests for equality with another BlockAddress.
        /// </summary>
        /// <param name="other">Other address to test.</param>
        /// <returns>True if addresses are equal; otherwise false.</returns>
        public bool Equals(BlockAddress other)
        {
            return this.offset == other.offset && this.segment == other.segment;
        }
        /// <summary>
        /// Tests for equality with another object.
        /// </summary>
        /// <param name="obj">Other object to test.</param>
        /// <returns>True if objects are equal; otherwise false.</returns>
        public override bool Equals(object obj)
        {
            if(obj is BlockAddress)
                return Equals((BlockAddress)obj);
            else
                return false;
        }
        /// <summary>
        /// Returns a value useful for hashing algorithms.
        /// </summary>
        /// <returns>Value useful for hashing algorithms.</returns>
        public override int GetHashCode()
        {
            return (int)(((uint)this.segment << 16) | this.offset);
        }
        /// <summary>
        /// Returns a string representation of the BlockAddress.
        /// </summary>
        /// <returns>String representation of the BlockAddress.</returns>
        public override string ToString()
        {
            return string.Format("{0:X4}:{1:X8}", this.segment, this.offset);
        }
    }
}
